﻿using Centny.PdfReader.Font;
using Centny.PdfReader.IO;
using Centny.PdfReader.Pdf;
using Centny.PdfReader.Types;
using Centny.PdfReader.util;
using CnyeCPlus.ExtSurface;
using CnyeCPlus.util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace Centny.PdfReader.Render
{
    public class PdfESurfaceImageFont : PdfFont
    {
        public ESurfaceImageSource ImgSource { get; set; }
        public bool IsFBuilderInit { get; set; }

        public PdfESurfaceImageFont(ESurfaceImageSource ImgSource, PdfDocument doc, PdfClassObject font, double fsize, double scale)
            : base(doc, font, fsize, scale)
        {
            this.ImgSource = ImgSource;
            this.IsFBuilderInit = false;
            switch (this.FontType)
            {
                case PdfFontType.MMType1:
                case PdfFontType.Type1:
                    //PdfLexer.End("LoadESurfaceFont-S");
                    //PdfTimer.SharedTimer.Beg();
                    if (this.FontFile != null)
                    {
                        Stream fs = this.FontFile.RStream();
                        byte[] bys = new byte[fs.Length];
                        fs.Read(bys, 0, (int)fs.Length);
                        this.ImgSource.CreateFBuilder(bys, 0);
                        this.ImgSource.SetFFontSize((float)(fsize * scale));
                        this.IsFBuilderInit = true;
                    }
                    //PdfTimer.SharedTimer.End("CreateFBuilder");
                    break;
            }
        }
        private async void S(byte[] bys)
        {

            StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("www.dat", CreationCollisionOption.OpenIfExists);
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                stream.AsStream().Write(bys, 0, bys.Length);
                await stream.FlushAsync();
            }
            //stream.AsStream().
        }
        public override Size CountGlyphSize(char c)
        {
            if (this.IsFBuilderInit)
            {
                return this.ImgSource.FCharGlyphSize(c);
            }
            else
            {
                return new Size(0, 0);
            }
        }

    }
    public class PdfImgSourcePage : PdfPage
    {
        public float Scale { get; set; }
        private ESurfaceImageSource _ImgSource;
        public ESurfaceImageSource ImgSource
        {
            get
            {
                return this._ImgSource;
            }
        }

        //
        public PdfImgSourcePage(PdfClassObject pco, float scale)
            : base(pco)
        {
            this.Scale = scale;
            this._ImgSource = new ESurfaceImageSource((int)(this.MediaBox.Width * this.Scale), (int)(this.MediaBox.Height * this.Scale), true);
            //this._ImgSource.ShowChar();
            this.Process();
        }
        public PdfImgSourcePage(PdfClassObject pco)
            : base(pco)
        {
            this.Scale = 1;
            this._ImgSource = new ESurfaceImageSource((int)(this.MediaBox.Width * this.Scale), (int)(this.MediaBox.Height * this.Scale), true);
            this.Process();
        }
        public override void Process(PdfStreamObject sobj)
        {
            StreamReader sr = new StreamReader(sobj.RStream());
            System.Diagnostics.Debug.WriteLine(sr.ReadToEnd());
            PdfImgStreamLexer pis = new PdfImgStreamLexer(this, sobj.RStream());
            pis.Scale = this.Scale;
            //PdfTimer t = new PdfTimer();
            pis.Process();
            //t.End("PdfImgStreamLexer.Process");
            //System.Diagnostics.Debug.WriteLine("tval:" + pis.tval);
        }
        public PdfESurfaceImageFont LoadESurfaceFont(PdfName fname, PdfDouble fsize)
        {
            //PdfTimer.SharedTimer.Beg();
            PdfClassObject cobj = this.LoadFont(fname);
            //PdfTimer.SharedTimer.End("LoadFont");
            PdfESurfaceImageFont sif = new PdfESurfaceImageFont(this.ImgSource, this.Doc, cobj, fsize.Val, this.Scale);
            return sif;
        }
    }

    //
    public class PdfImgStreamLexer : PdfStreamLexer
    {
        public float Scale { get; set; }
        public PdfImgSourcePage Page { get; set; }
        //
        public PdfImgStreamLexer(PdfImgSourcePage page, Stream s)
            : base(s)
        {
            this.Page = page;
            this.Scale = 1;
        }
        public override void OnBegText()
        {
            base.OnBegText();
            this.Page.ImgSource.BeginDraw();
            this.Page.ImgSource.Clear(Colors.White);
        }
        public override void OnEndText()
        {
            base.OnEndText();
            this.Page.ImgSource.EndDraw();
        }
        private Dictionary<PdfName, PdfFont> NFonts = new Dictionary<PdfName, PdfFont>();
        private Dictionary<PdfClassObject, Dictionary<char, Size>> DesiredSizes_ = new Dictionary<PdfClassObject, Dictionary<char, Size>>();
        public override void SetFontNameSize(Types.PdfName fname, Types.PdfDouble fsize)
        {
            //if (count > 50)
            //{
            //    return;
            //}
            //fsize.Val = 100;
            //PdfTimer.SharedTimer.Beg();
            PdfFont font;
            if (this.NFonts.ContainsKey(fname))
            {
                font = this.NFonts[fname];
            }
            else
            {
                font = this.Page.LoadESurfaceFont(fname, fsize);
            }
            this.GraphicsState.TextState.Font = font;
            this.GraphicsState.TextState.FontName = fname;
            //PdfTimer.SharedTimer.End("LoadESurfaceFont");
            this.Page.ImgSource.CreateTextFormat(font.BaseFont.NName, (float)(0.8 * fsize.Val * this.GraphicsState.TextState.Font.Scale));
            this.TextState.Set(0, 0, this.GraphicsState.TextState.Font.FontSize * this.GraphicsState.TextState.HorizontalScaling / 100);
            this.TextState.Set(1, 1, this.GraphicsState.TextState.Font.FontSize);
            //base.SetFontNameSize(fname, fsize);
        }
        public override void SetHorScaling(PdfDouble hs)
        {
            //hs.Val *= this.GraphicsState.Scale;
            base.SetHorScaling(hs);
            this.TextState.Set(0, 0, this.GraphicsState.TextState.Font.FontSize * this.GraphicsState.TextState.HorizontalScaling / 100);
        }
        //
        public int tval = 0;
        private PdfMatrix TextState = new PdfMatrix();
        //private int count = 0;
        public override void OnDraw(PdfString text)
        {
            //if (count >50)
            //{
            //    return;
            //}
            //this.count++;
            //PdfLexer.End("OnDraw-S");
            Dictionary<char, Size> csize;
            if (this.DesiredSizes_.ContainsKey(this.GraphicsState.TextState.Font.Font))
            {
                csize = this.DesiredSizes_[this.GraphicsState.TextState.Font.Font];
            }
            else
            {
                csize = new Dictionary<char, Size>();
            }
            this.TextState.Set(2, 1, this.GraphicsState.TextState.Rise);
            PdfMatrix StartMatrix = new PdfMatrix();
            PdfMatrix td = new PdfMatrix();
            //
            CharRect cr;
            //String sdata = text.Data;
            double horizontalScalingText = this.GraphicsState.TextState.HorizontalScaling / 100f;
            char[] tdata = text.Data.ToCharArray();
            List<CharRect> allrts = new List<CharRect>();
            //
            for (int i = 0; i < tdata.Length; i++)
            {
                char c = tdata[i];
                Size DesiredSize;
                if (csize.ContainsKey(c))
                {
                    DesiredSize = csize[c];
                }
                else
                {
                    DesiredSize = this.GraphicsState.TextState.Font.GlyphSize(c);
                    csize[c] = DesiredSize;
                }
                bool unabledraw = DesiredSize.Width < 1;
                if (unabledraw)
                {
                    TextBlock tb = new TextBlock();
                    tb.FontFamily = new FontFamily(this.GraphicsState.TextState.Font.BaseFont.NName);
                    tb.FontSize = this.GraphicsState.TextState.Font.RealFontSize * 0.8;
                    tb.Text = "" + c;
                    tb.Measure(new Size(Double.MaxValue, Double.MaxValue));
                    DesiredSize = tb.DesiredSize;
                    DesiredSize.Height *= 0.7;
                }
                //if (c < 255 && (!Char.IsLetterOrDigit(c)))
                //{
                //    continue;
                //}
                double rwidth = DesiredSize.Width;
                if (c == 0x20)
                {
                    rwidth = (this.GraphicsState.TextState.Font.FontSize / 1000f
                        + this.GraphicsState.TextState.CharacterSpacing
                        + this.GraphicsState.TextState.WordSpacing)
                        * horizontalScalingText * this.Scale;
                }
                else
                {
                    rwidth = (0.6 * this.GraphicsState.TextState.Font.FontSize + this.GraphicsState.TextState.CharacterSpacing)
                        * horizontalScalingText * this.Scale;
                }
                if (rwidth > 0)
                {
                    DesiredSize.Width = rwidth;
                }
                else
                {
                    DesiredSize.Width = 0;
                }
                this.GraphicsState.TextState.TextMatrix.Multiply(this.GraphicsState.Ctm, StartMatrix);
                this.TextState.Multiply(StartMatrix, StartMatrix);
                //
                Rect rt = new Rect();
                rt.X = StartMatrix.Get(2, 0) * this.Scale;
                rt.Y = (this.Page.MediaBox.Height - StartMatrix.Get(2, 1)) * this.Scale + (this.GraphicsState.TextState.Font.RealFontSize - DesiredSize.Height);
                rt.Width = DesiredSize.Width;
                rt.Height = DesiredSize.Height;
                if (c != 0x20)
                {
                    if (unabledraw)
                    {
                        this.Page.ImgSource.DrawText("" + c, Colors.Black, rt);
                    }
                    else
                    {
                        switch (c)
                        {
                            case 'p':
                            case 'y':
                            case 'g':
                                rt.Y += this.GraphicsState.TextState.Font.FontSize * this.GraphicsState.TextState.Font.Scale * 0.2;
                                break;
                        }
                        //this.Page.ImgSource.DrawFText(c, rt, Colors.Black);
                        //this.tval += this.Page.ImgSource.Tval;
                        allrts.Add(CreateCRect(c, rt));
                        //System.Diagnostics.Debug.WriteLine("tval:" + this.Page.ImgSource.Tval);
                    }
                }
                //
                td.Set(2, 0, DesiredSize.Width / this.Scale);
                td.Multiply(this.GraphicsState.TextState.TextMatrix, this.GraphicsState.TextState.TextMatrix);

            }
            this.DesiredSizes_[this.GraphicsState.TextState.Font.Font] = csize;
            //PdfTimer.SharedTimer.Beg();
            this.Page.ImgSource.DrawFText(allrts.ToArray(), Colors.Black);
            //PdfTimer.SharedTimer.Delay();
            //System.Diagnostics.Debug.WriteLine("time:" + Timer.Now);
        }
        public static CharRect CreateCRect(char c, Rect rt)
        {
            CharRect cr = new CharRect();
            cr.Tchar = c;
            cr.Rt = rt;
            return cr;
        }
    }

}
